Asynchronous timers provide IDL with non-blocking timers. They offer the following advantages over widget-based asynchronous timers:
Asynchronous timers can fire and have their callback invoked in these situations:
Asynchronous timers will not fire in these situations:
While system callbacks are executing. Some examples of callbacks are: timer callbacks, widget event handlers, object cleanup methods, etc. When a timer fires while a callback is executing, its callback will be invoked when the current one finishes.
Note: Asynchronous timers in IDL are actually implemented as a collection of static methods. Because of this, there are no "Creation" or "Syntax" sections in this document for creating timers.
Additional Information on Timers
;--------------------------------------------------------------------
; This program demonstrates simple usage of IDL asynchronous timers. A timer
; is created and it fires once. User data is passed to the timer's callback.
; The callback prints the timer's identifier and user data.
PRO myTimerCallback, id, userData
COMPILE_OPT IDL2
PRINT, 'myTimerCallback( ', STRTRIM( id, 2 ), ', ', userData, ' )'
END
PRO async_timer_example_1
COMPILE_OPT IDL2
; Create a timer that will fire in 3.14 seconds. The name of the callback is
; required but the user data is optional. The user data can be a string,
; structure, hash, etc.
id = Timer.Set( 3.14, 'myTimerCallback', 'woof' )
END
;--------------------------------------------------------------------
; This program demonstrates usage of IDL asynchronous timers with objects.
; A main program creates an object and then a timer is set on that object.
; When the timer fires, the object's "handleTimerEvent" method is invoked.
;
; Run this example by saving it as "asynctimerexample2__define.pro".
;--------------------------------------------------------------------
; AsyncTimerExample2 class
;
; The class must implement a method with the name "handleTimerEvent". This
; callback method's signature is the same as with timer callback procedures.
PRO AsyncTimerExample2::handleTimerEvent, id, userData
COMPILE_OPT IDL2
PRINT, 'AsyncTimerTester::handleTimerEvent( ', STRTRIM( id, 2 ), ', ', userData, ' )'
END
PRO AsyncTimerExample2__define
COMPILE_OPT IDL2
!null = { AsyncTimerExample2, $
INHERITS IDL_Object $
}
END
;--------------------------------------------------------------------
; main program
o = AsyncTimerExample2()
id = Timer.Set( 3.14, o, 'w' + 'o' + 'o' + 'f' )
END
; This program demonstrates the use of timer.Block and timer.Unblock
; to create a region of code that will not be interrupted by timer
; callbacks.
;
; A pointer to some "critical data" is created. Both the main
; routine and timer callback can modify this. Calls to timer.Block
; and timer.Unblock prevent the timer from altering the value
; before the main routine is done with it. As soon as the safe
; zone is exited, the timer is allowed to fire.
;
; Note that the "busyWait" routine gives the timer every chance to
; execute, because timers can interrupt PRO code execution.
PRO handleTimer, id, userData
COMPILE_OPT IDL2
PRINT, '*** Timer Fired ***'
*userData = 0
END
PRO busyWait, t
COMPILE_OPT IDL2
t0 = SYSTIME( /SECONDS )
WHILE ( ( SYSTIME( /SECONDS ) - t0 ) lt t ) DO BEGIN
ENDWHILE
END
PRO async_timer_example_3
COMPILE_OPT IDL2
criticalData = PRT_NEW( 1 )
!NULL = timer.Set( 1.0, 'handleTimer', criticalData )
PRINT, 'Data before safe zone: ', STRTRIM( *criticalData, 2 )
timer.Block
busyWait, 2.0
PRINT, 'Data in safe zone: ', STRTRIM( *criticalData, 2 )
timer.Unblock
PRINT, 'Data after safe zone: ', STRTRIM( *criticalData, 2 )
END
The Timer::Block method allows you to block an asynchronous timer. If a timer's callback code could potentially interrupt and disrupt other code, the timer should be blocked. An example is when the timer's calleback code could access the same data as the code that it might interrupt. See Example 3.
Code that runs in between the calls to Block and Unblock will not be interrupted by any timer. IDL automatically blocks timer callbacks from interrupting system callbacks, including timer callbacks, widget callbacks, drag and drop callbacks, etc. Explicit blocking is unnecessary in these types of callbacks. Invocations of the Fire method will work regardless of blocking.
The Block and Unblock methods must always be paired. They can be nested. If they are not paired, then timer blocking will not work as expected. To help debug mismatches, the procedures have a COUNT keyword that returns the current nesting level after the call to block or unblock. The returned value typically ranges from 0 to MaxLong, where 0 means blocking will not occur and values greater than 0 indicate the nesting level. Negative values indicate that too many calls to Unblock have been made, and Block and Unblock have not been correctly paired.
Timer.Block [, COUNT]
None
Set this keyword to a named variable that will contain a long integer with the nesting level of the Block and Unblock methods.
The Timer::Cancel method cancels a timer. Note that timers can be canceled, either one at a time or all at the same time.
Result = Timer.Cancel( ID )
Result = Timer.Cancel( ALL=value )
Returns a 0 or 1 to indicate the success or failure of the call. A return value of 1 indicates the call was successful, while a 0 indicates that the identifier (id) was invalid and the call was not successful.
A long integer that is the timer's identifier. This is the same value as returned by the "set" function.
Use in place of ID to indicate whether all timers should be canceled. Valid values are Boolean (1 for yes or 0 for no).
Note: If you specify /ALL (or ALL = 1) in conjunction with the ID argument, the /ALL takes precedence and IDL ignores the ID.
You can launch a timer immediately, before it expires, by using the Timer.Fire method. If you originally supply user data, it is replaced with the new user data.
Note: If you use Timer::Fire, the timer will be "complete" and will not go off again.
Result = Timer.Fire( ID [, UserData ] )
Returns a 0 or 1 to indicate the success or failure of the call. A return value of 1 indicates the call was successful, while a 0 indicates that the identifier (ID) was invalid and the call was not successful.
The timer's identifier (a long integer). This is the same value as returned by the "set" function.
Optional data to supply to the callback when you invoke it. This data replaces any user data specified when the timer was created.
None.
The Timer::Set method allows you to create an asynchronous timer.
You have two options available to create a timer. The first requires the specification of a callback procedure. The second requires an object that must have a method named handleTimerEvent.
In both cases user data is optional. The returned value is the timer's identifier, which can be used to cancel the timer or fire the timer early.
Note: Once IDL invokes the timer, its identifier is no longer valid. Namely, the <ID> cannot be used to cancel or fire the timer.
ID = Timer.Set( Time, Callback [, UserData])
ID = Timer.Set( Time, Object [, UserData])
Returns the ID (identifier) of the timer. Use this ID with the Timer::Cancel and Timer::Fire methods.
The amount of time in seconds until the timer should activate.
A string value specifying the name of the procedure that IDL should invoke when the timer activates.
The callback must have the following signature:
PRO Name, ID [, UserData]
| Value | Type | Description |
|---|---|---|
| Name | Name of the routine. When the timer is set using an object, this must be of the form <class>::handleTimerEvent. |
|
| ID | Long |
The timer's identifier. This is the same value as returned by the "set" function. |
| UserData | Any | The data supplied when the timer was set. |
Object on which to call a method named handleTimerEvent when the timer activates.
Data to be delivered to the callback. The delivered data will be a copy of the original. If user data is not supplied then the callback receives !NULL. UserData can be any valid IDL value. Examples of valid IDL values include: a constant, variable, expression, an array, etc.
None.
The Timer::Block method allows you to unblock asynchronous timers that have been blocked.
Timer.Unblock [, COUNT]
None
Set this keyword to a named variable that will contain a long integer with the nesting level of the Block and Unblock methods.
The table below lays out the main differences between Widget-based and Asynchronous Timers:
| Feature | Widget Timers | Asynchronous Timers |
|---|---|---|
| Interrupt PRO code | No | Yes |
| Interrupt C code | No | No |
| Interrupt WAIT | No | No |
| Interrupt callbacks | No | No |
| Modal bases | Will not fire until modal child dismissed. | Fires even when modal base is present. |
| Floating base | Fires even when floating base is present. | Fires even when floating base is present. |
| Native dialogs* | Will not fire until dialog is dismissed. | Will not fire until dialog is dismissed. |
| Blocking Xmanager | No difference. | No difference. |
| Runtime/VM mode |
* The set of native dialogs include:
You can reset timers using any of the following actions:
| Action | Effect |
|---|---|
| .RESET_SESSION | Cancels all pending timers and resets the timer identifiers back to a value of 1. |
| .FULL_RESET_SESSION | Cancels all pending timers and resets the timer identifiers back to a value of 1. |
| <CTRL><C> | Cancels all pending timers. |
| "STOP" button in the IDL Workbench | Cancels all pending timers. |
Timers alone will not keep an IDL runtime or virtual machine running. In those run modes, IDL runs a single routine and then exits, regardless of pending asynchronous timers.
|
8.3 |
Introduced |
|
8.4 |
Added Block and Unblock methods; IDL no longer automatically interrupts callbacks. |